﻿using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using DarkAngels.WoW.Library.Armory.Character;

namespace SmartDeviceProject1.Controls
{
    class CharacterListBox : OwnerDrawnListBox
    {
        const int FONT_SIZE = 10;
        const int DRAW_OFFSET = 5;

        public CharacterListBox()
        {
            int value = Math.Max(64, (this.ClientSize.Height / 4));
            int leftOver = this.ClientSize.Height % value;
            double items = Math.Floor(this.ClientSize.Height / (double)value);
            int split = leftOver / (int)items;
            this.ItemHeight = value + split;
        }

        // Return the name of the selected font.
        public Character SelectedCharacter
        {
            get
            {
                return (Character)this.Items[this.SelectedIndex];
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            // The base class contains a bitmap, offScreen, for constructing
            // the control and is rendered when all items are populated.
            // This technique prevents flicker.
            Graphics gOffScreen = Graphics.FromImage(this.OffScreen);
            //gOffScreen.FillRectangle(new SolidBrush(this.BackColor), this.ClientRectangle);
            //GradientFill.Fill(gOffScreen, new Rectangle(0, 0, this.Width, this.Height), Color.FromArgb(1, 74, 127), Color.FromArgb(1, 148, 254), GradientFill.FillDirection.TopToBottom);
            GradientFill.Fill(gOffScreen, new Rectangle(0, 0, this.ClientSize.Width, this.ClientSize.Height), Color.FromArgb(1, 148, 254), Color.FromArgb(1, 74, 127), GradientFill.FillDirection.LeftToRight);

            int itemTop = 0;

            // Draw the fonts in the list.
            for (int n = this.VScrollBar.Value; n < this.VScrollBar.Value + DrawCount; n++)
            {
                // Draw the selected item to appear highlighted
                if (n == this.SelectedIndex)
                {
                    GradientFill.Fill(
                        gOffScreen,
                        new Rectangle(0, itemTop, this.ClientSize.Width - (this.VScrollBar.Visible ? this.VScrollBar.Width : 2), this.ItemHeight),
                        Color.FromArgb(1, 74, 127),
                        Color.FromArgb(1, 148, 254),
                        GradientFill.FillDirection.LeftToRight
                    );
                    gOffScreen.DrawRectangle(new Pen(Color.White, 1F), new Rectangle(0, itemTop, this.ClientSize.Width - ((this.VScrollBar.Visible ? this.VScrollBar.Width : 2) + 1), this.ItemHeight- 1));
                }
                else
                {
                    GradientFill.Fill(
                        gOffScreen,
                        new Rectangle(0, itemTop, this.ClientSize.Width - (this.VScrollBar.Visible ? this.VScrollBar.Width : 2), this.ItemHeight),
                        Color.FromArgb(1, 148, 254),
                        Color.FromArgb(1, 74, 127),
                        GradientFill.FillDirection.LeftToRight
                    );
                }

                // Draw the item
                gOffScreen.DrawImage(
                    LocalAvatar(
                        (Character)this.Items[n])
                        , new Rectangle(
                            0
                            , itemTop + 1
                            , Math.Min(64, this.ItemHeight)
                            , Math.Min(64, this.ItemHeight))
                        , new Rectangle(0, 0, 64, 64)
                        , GraphicsUnit.Pixel
                    );
                gOffScreen.DrawString(FullName((Character)this.Items[n]), new Font("Times New Roman", 10F, FontStyle.Regular), new SolidBrush(Color.Black), DRAW_OFFSET + Math.Min(64, this.ItemHeight), itemTop);
                gOffScreen.DrawString(Line2((Character)this.Items[n]), new Font("Times New Roman", 10F, FontStyle.Regular), new SolidBrush(Color.Black), DRAW_OFFSET + Math.Min(64, this.ItemHeight), itemTop + 12);
                itemTop += this.ItemHeight;
            }

            // Draw the list box
            e.Graphics.DrawImage(this.OffScreen, 1, 1);

            gOffScreen.Dispose();
        }

        string FullName(Character c)
        {
            return (c.Prefix + c.CharacterName.Substring(0, 1).ToUpper() + c.CharacterName.Substring(1, c.CharacterName.Length-1).ToLower() + c.Suffix).Trim();
        }
        string Line2(Character c)
        {
            return ("<" + c.GuildName + "> of ").Replace("<> of ", "") + c.RealmName;
        }
        Image LocalAvatar(Character c)
        {
            string l = "";
            if (c.Level >= 80)
                l = "80_89";
            else if (c.Level >= 70)
                l = "70_79";
            else if (c.Level >= 60)
                l = "60_69";
            else
                l = "1_59";
            return (Image)Properties.Resources.ResourceManager.GetObject("_" + l + "_" + c.GenderId + "_" + c.RaceId + "_" + c.ClassId);
            //source: http://bytes.com/groups/net-c/564621-dynamic-resource-naming
        }

        // Draws the external border around the control.
        protected override void OnPaintBackground(PaintEventArgs e)
        {
            e.Graphics.DrawRectangle(new Pen(Color.Black), 0, 0, this.ClientSize.Width - 1, this.ClientSize.Height - 1);
        }
    }

    public sealed class Win32Helper
    {
        public struct TRIVERTEX
        {
            public int x;
            public int y;
            public ushort Red;
            public ushort Green;
            public ushort Blue;
            public ushort Alpha;
            public TRIVERTEX(int x, int y, Color color)
                : this(x, y, color.R, color.G, color.B, color.A)
            {
            }
            public TRIVERTEX(
                int x, int y,
                ushort red, ushort green, ushort blue,
                ushort alpha)
            {
                this.x = x;
                this.y = y;
                this.Red = (ushort)(red << 8);
                this.Green = (ushort)(green << 8);
                this.Blue = (ushort)(blue << 8);
                this.Alpha = (ushort)(alpha << 8);
            }
        }
        public struct GRADIENT_RECT
        {
            public uint UpperLeft;
            public uint LowerRight;
            public GRADIENT_RECT(uint ul, uint lr)
            {
                this.UpperLeft = ul;
                this.LowerRight = lr;
            }
        }


        [DllImport("coredll.dll", SetLastError = true, EntryPoint = "GradientFill")]
        public extern static bool GradientFill(
            IntPtr hdc,
            TRIVERTEX[] pVertex,
            uint dwNumVertex,
            GRADIENT_RECT[] pMesh,
            uint dwNumMesh,
            uint dwMode);

        public const int GRADIENT_FILL_RECT_H = 0x00000000;
        public const int GRADIENT_FILL_RECT_V = 0x00000001;

    }
    public sealed class GradientFill
    {
        // This method wraps the PInvoke to GradientFill.
        // Parmeters:
        //  gr - The Graphics object we are filling
        //  rc - The rectangle to fill
        //  startColor - The starting color for the fill
        //  endColor - The ending color for the fill
        //  fillDir - The direction to fill
        //
        // Returns true if the call to GradientFill succeeded; false
        // otherwise.
        public static bool Fill(
            Graphics gr,
            Rectangle rc,
            Color startColor, Color endColor,
            FillDirection fillDir)
        {

            // Initialize the data to be used in the call to GradientFill.
            Win32Helper.TRIVERTEX[] tva = new Win32Helper.TRIVERTEX[2];
            tva[0] = new Win32Helper.TRIVERTEX(rc.X, rc.Y, startColor);
            tva[1] = new Win32Helper.TRIVERTEX(rc.Right, rc.Bottom, endColor);
            Win32Helper.GRADIENT_RECT[] gra = new Win32Helper.GRADIENT_RECT[] {
    new Win32Helper.GRADIENT_RECT(0, 1)};

            // Get the hDC from the Graphics object.
            IntPtr hdc = gr.GetHdc();

            // PInvoke to GradientFill.
            bool b;

            b = Win32Helper.GradientFill(
                    hdc,
                    tva,
                    (uint)tva.Length,
                    gra,
                    (uint)gra.Length,
                    (uint)fillDir);
            System.Diagnostics.Debug.Assert(b, string.Format(
                "GradientFill failed: {0}",
                System.Runtime.InteropServices.Marshal.GetLastWin32Error()));

            // Release the hDC from the Graphics object.
            gr.ReleaseHdc(hdc);

            return b;
        }

        // The direction to the GradientFill will follow
        public enum FillDirection
        {
            //
            // The fill goes horizontally
            //
            LeftToRight = Win32Helper.GRADIENT_FILL_RECT_H,
            //
            // The fill goes vertically
            //
            TopToBottom = Win32Helper.GRADIENT_FILL_RECT_V
        }
    }
}
